/*
 * CabinetManager.java
 *
 *  
 */
package org.msb.finance.app;

import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.jdo.*;

import org.msb.finance.data.Cabinet;
import org.msb.finance.util.PasswordHasher;

/**
 * The {@code CabinetManager} class manages the currently opened {@link Cabinet} object as well as pushing updates to
 * the underlying data store.
 * 
 * @author Marc Boudreau
 */
public class CabinetManager {

	/*
	 * The currently opened Cabinet object, or null if there isn't an opened Cabinet.
	 */
	private Cabinet cabinet;

	/*
	 * The factory class used to build PersistenceManager objects needed to interact with the data store.
	 */
	private PersistenceManager pm;

	/**
	 * 
	 * @param file
	 * @param password
	 */
	@SuppressWarnings("unchecked")
	public CabinetManager(File file, char[] password) {
		Map<String, String> props = buildJDOProperties(convertFileToString(file));

		String hashedPassword = PasswordHasher.hash(password);

		this.pm = getPersistenceManagerFactory(props).getPersistenceManager();
		Transaction tx = pm.currentTransaction();

		try {
			tx.begin();

			Query q = pm.newQuery(Cabinet.class);
			q.setFilter("this.password.equals(\"" + hashedPassword + "\")"); //$NON-NLS-1$ //$NON-NLS-2$

			Collection<Cabinet> cabinets = (Collection<Cabinet>) q.execute();
			assert 1 >= cabinets.size() : "Collection of Cabinets is never supposed to have more than 1 element"; //$NON-NLS-1$

			if (0 == cabinets.size()) {
				this.cabinet = new Cabinet(hashedPassword);
			} else {
				this.cabinet = cabinets.iterator().next();
			}
		} catch (Throwable th) {
			System.err.println(th.getMessage());
			th.printStackTrace();
		}
	}

	/*
	 * Converts a File object into a String containing the URI representation of the provided File object.
	 */
	static String convertFileToString(File file) {
		return file.toURI().toString();
	}

	/*
	 * Builds a map of JDO properties used to construct the PersistenceManagerFactory object.
	 */
	static Map<String, String> buildJDOProperties(String filename) {
		final String empty = new String();
		HashMap<String, String> props = new HashMap<String, String>();
		props.put("javax.jdo.option.ConnectionDriverName", empty); //$NON-NLS-1$
		props.put("javax.jdo.option.ConnectionURL", "db4o:" + filename); //$NON-NLS-1$ //$NON-NLS-2$
		props.put("javax.jdo.option.ConnectionUserName", empty); //$NON-NLS-1$
		props.put("javax.jdo.option.ConnectionPassword", empty); //$NON-NLS-1$
		props.put("javax.jdo.PersistenceManagerFactoryClass", "org.jpox.jdo.JDOPersistenceManagerFactory"); //$NON-NLS-1$ //$NON-NLS-2$

		return props;
	}

	/*
	 * Returns the PersistenceManagerFactory object for this instance.
	 */
	PersistenceManagerFactory getPersistenceManagerFactory(Map<String, String> props) {
		PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props);

		return pmf;
	}

	/**
	 * 
	 * @return s
	 */
	public Cabinet getCabinet() {
		return this.cabinet;
	}

	/**
	 * 
	 */
	public void updateCabinet() {
		Transaction tx = this.pm.currentTransaction();
		assert tx.isActive() : "Expected the current transaction to still be active."; //$NON-NLS-1$

		if (!tx.isActive()) {
			tx.begin();
		}

		pm.makePersistent(this.cabinet);

		tx.commit();
		tx.begin();
	}

	/**
	 * 
	 */
	public void close() {
		Transaction tx = this.pm.currentTransaction();

		if (!tx.isActive()) {
			tx.begin();
		}

		this.pm.makePersistent(this.cabinet);

		tx.commit();

		this.pm.close();
		this.pm.getPersistenceManagerFactory().close();
	}
}
